package pers.chao.cacheable.core;

import pers.chao.cacheable.core.annotation.CacheList;
import pers.chao.cacheable.core.consts.PushDirection;
import pers.chao.cacheable.infrastructure.ErrorDesc;
import pers.chao.cacheable.core.consts.EvictEqType;
import pers.chao.cacheable.infrastructure.utils.ElementUtil;
import pers.chao.cacheable.infrastructure.utils.RedisOp;
import pers.chao.tool.spring.SpringElUtil;
import pers.chao.tool.validate.ObjValidator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Description: list缓存操作
 * <p>
 * 执行顺序：
 * 删除key(或删除该key的所有元素) -> 清除所有等值元素 -> 修剪元素 -> 缓存元素
 * <p>
 * note：删除key或修剪元素不再继续它的后续操作
 *
 * @author W.Chao
 * @date 2020/10/2 14:32
 **/
public class CacheListProcessor extends AbstractCacheProcessor {
	private CacheList annotation;

	public CacheListProcessor(CacheList annotation) {
		this.annotation = annotation;
	}

	@Override
	protected void preInfo() {
		logger.info("[Cache list pre INFO], @cache -> {}, @cacheList -> {}", cacheConditionInfo(), annotation);
	}

	@Override
	public void parseRedisStructKeyOrOther() {

	}

	@Override
	public Object preQuery() {
		if (RedisOp.hasKey(finalKey)) {
			return RedisOp.lGet(finalKey, 0, -1);
		}
		return null;
	}

	@Override
	public void afterMethodOperate(Object o) {
		PushDirection pushDirection = annotation.pushDirection();
		ArrayList<Integer> trimIndex = Arrays.stream(annotation.trim()).collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
		boolean isReplaceAll = annotation.replaceAll();

		// 删除key
		if (evict) {
			RedisOp.del(finalKey);
			return;
		} else if (isReplaceAll) {
			// 整体替换时先将所有元素清除(保留key)
			RedisOp.trim(finalKey, 1, 0);
		}

		// 清除列表中的等值元素
		String evictEqValue = SpringElUtil.parseSpringEL(method, params.values().toArray(), annotation.evictEq(), String.class, annotation.evictEq());
		Object transfer = evictEqValue;
		EvictEqType evictEqType = annotation.eqValueType();
		// 类型转换，redisTemplate有类型判断，需要和插入时的类型相同才可等值删除
		if (evictEqType == EvictEqType.LONG){
			transfer = Long.valueOf(evictEqValue);
		}else if (evictEqType == EvictEqType.DOUBLE){
			transfer = Double.valueOf(evictEqValue);
		}else if (evictEqType==EvictEqType.INTEGER){
			transfer = Integer.valueOf(evictEqValue);
		}else if (evictEqType==EvictEqType.FLOAT){
			transfer = Float.valueOf(evictEqValue);
		}else if (evictEqType==EvictEqType.BOOLEAN){
			transfer = Boolean.valueOf(evictEqValue);
		}else if (evictEqType==EvictEqType.BYTE){
			transfer = Byte.valueOf(evictEqValue);
		}else if (evictEqType == EvictEqType.STRING){
			transfer = String.valueOf(evictEqValue);
		}

		if (!ObjValidator.isEmptyObj(transfer)) {
			RedisOp.lRemove(finalKey, 0, transfer); // 所有
		}

		// 修剪
		if (ObjValidator.isNotEmptyCollection(trimIndex)) {
			if (trimIndex.size() != 2) {
				throw new CacheableException(ErrorDesc.LIST_TRIM_INDEX_ERROR, trimIndex);
			}
			RedisOp.trim(finalKey, trimIndex.get(0), trimIndex.get(1));
			return;
		}

		// 将元素封装到列表中
		List<Object> elements = ElementUtil.elementTransfer(o);

		if (RedisOp.hasKey(finalKey)) {
			if (PushDirection.RIGHT.equals(pushDirection)) {
				RedisOp.lrPushAll(finalKey, elements);
			} else {
				RedisOp.llPushAll(finalKey, elements);
			}
		} else {
			// 未存在key的情况下才能设置过期时间
			if (PushDirection.RIGHT.equals(pushDirection)) {
				// 过期期限
				if (isNeedExpire) {
					RedisOp.lrPushAll(finalKey, elements, expire, unit);
				} else {
					RedisOp.lrPushAll(finalKey, elements);
				}
			} else {
				if (isNeedExpire) {
					RedisOp.llPushAll(finalKey, elements, expire, unit);
				} else {
					RedisOp.llPushAll(finalKey, elements);
				}
			}
		}
	}
}
